﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Microsoft.Win32;
using System.ComponentModel;
using System.IO;
using System.Globalization;

namespace JJCraft
{
    /// <summary>
    /// Interaction logic for JJCraftWindow.xaml
    /// </summary>
    public partial class JJCraftWindow : Window
    {
        public JJCraftWindow()
        {
            InitializeComponent();
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            JJCraft.Properties.Settings.Default.Save();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            textLogFileName.Text = Properties.Settings.Default.LastLogFile;
        }

        private void buttonExit_Click(object sender, RoutedEventArgs e)
        {
            Application.Current.Shutdown();
        }

        private void buttonBrowseLogFile_Click(object sender, RoutedEventArgs e)
        {
            string openDirectory = string.Empty;
            if(!String.IsNullOrEmpty(Properties.Settings.Default.LastLogFile))
            {
                openDirectory = System.IO.Path.GetDirectoryName(Properties.Settings.Default.LastLogFile);
            }

            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Title = "打开战斗日志文件";
            dialog.Multiselect = false;
            
            if (!String.IsNullOrEmpty(openDirectory))
            {
                dialog.InitialDirectory = openDirectory;
            }
            dialog.CheckFileExists = true;

            bool? result = dialog.ShowDialog(this);
            if(result.HasValue && result.Value)
            {
                textLogFileName.Text = dialog.FileName;
            }
        }

        private void StartParse()
        {
            Properties.Settings.Default.LastLogFile = textLogFileName.Text;
            Properties.Settings.Default.LastChatLogFile = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(Properties.Settings.Default.LastLogFile), "WowChatLog.txt");

            if (File.Exists(Properties.Settings.Default.LastChatLogFile) && File.Exists(Properties.Settings.Default.LastLogFile))
            {
                mLastResultCount = 0;

                progressBar.Value = 0;
                progressBar.Visibility = Visibility.Visible;
                buttonParse.IsEnabled = false;
                buttonParse.Content = "正在分析...";

                BackgroundWorker parseWorker = new BackgroundWorker();
                parseWorker.WorkerSupportsCancellation = false;
                parseWorker.WorkerReportsProgress = true;

                parseWorker.DoWork += new DoWorkEventHandler(parseWorker_DoWork);
                parseWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(parseWorker_RunWorkerCompleted);
                parseWorker.ProgressChanged += new ProgressChangedEventHandler(parseWorker_ProgressChanged);

                parseWorker.RunWorkerAsync();
            }
            else
            {
                MessageBox.Show("找不到战斗日志文件或相关联的WowChatLog.txt, 无法进行分析.", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
            }
        }

        private void buttonParse_Click(object sender, RoutedEventArgs e)
        {
            StartParse();
        }

        private void AddResult(Combat combat)
        {
            if (groupResults.Visibility == Visibility.Collapsed)
            {
                groupResults.Visibility = Visibility.Visible;
            }

            List<Unit> friends = combat.Friends;
            List<Unit> enemies = combat.Enemies;

            string[] friendNames = new string[friends.Count];
            string[] enemyNames = new string[enemies.Count];

            for (int i = 0; i < friends.Count; ++i)
            {
                friendNames[i] = String.Format("[{0}]{1}", ClassManager.Singleton.GetClassShortName(friends[i].Class), friends[i].Name);
            }

            for (int i = 0; i < enemies.Count; ++i)
            {
                enemyNames[i] = String.Format("[{0}]{1}", ClassManager.Singleton.GetClassShortName(enemies[i].Class), enemies[i].Name);
            }

            string resultStr = string.Empty;
                switch (combat.Result)
                {
                    case CombatResult.Win:
                        resultStr = "胜";
                        break;
                    case CombatResult.Lose:
                        resultStr = "败";
                        break;
                    case CombatResult.DrawGame:
                        resultStr = "平";
                        break;
                }

            StackPanel itemPanel = new StackPanel();
            itemPanel.Orientation = Orientation.Vertical;
            itemPanel.Tag = combat;

            Label labelTime = new Label();
            labelTime.FontWeight = FontWeights.Bold;
            labelTime.Content = String.Format("[{2}] 开始: {0}, 持续: {1}", combat.StartTime.ToShortTimeString(), (combat.EndTime - combat.StartTime).ToString(), resultStr);

            Label labelFriends = new Label();
            labelFriends.Margin = new Thickness(10, 0, 0, 0);
            labelFriends.Content = String.Format("我方: {0}", String.Join(", ", friendNames));

            Label labelEnemies = new Label();
            labelEnemies.Margin = new Thickness(10, 0, 0, 0);
            labelEnemies.Content = String.Format("敌方: {0}", String.Join(", ", enemyNames));

            itemPanel.Children.Add(labelTime);
            itemPanel.Children.Add(labelFriends);
            itemPanel.Children.Add(labelEnemies);

            listResults.Items.Add(itemPanel);

            if (listResults.Items.Count > 0)
            {
                buttonClear.Visibility = Visibility.Visible;
            }
        }

        private int mLastResultCount;

        void parseWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar.Value = e.ProgressPercentage;

            LogParseResult result = e.UserState as LogParseResult;
            int currentResultCount = result.Combats.Count;

            if (currentResultCount > mLastResultCount)
            {
                for (int i = mLastResultCount; i < currentResultCount; ++i)
                {
                    AddResult(result.Combats[i]);
                }

                mLastResultCount = currentResultCount;
            }
        }

        void parseWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            buttonParse.IsEnabled = true;
            buttonParse.Content = "开始分析";
            progressBar.Visibility = Visibility.Collapsed;

            LogParseResult result = e.Result as LogParseResult;
            int currentResultCount = result.Combats.Count;

            if (currentResultCount > mLastResultCount)
            {
                for (int i = mLastResultCount; i < currentResultCount; ++i)
                {
                    AddResult(result.Combats[i]);
                }

                mLastResultCount = currentResultCount;
            }
        }

        void parseWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            LogParseResult result = new LogParseResult();

            LogReader logReader = new LogReader();

            StreamReader chatReader = new StreamReader(Properties.Settings.Default.LastChatLogFile, Encoding.UTF8);

            int lineCount = 0;

            int chatState = 0;

            List<DateTime> combatTimePoints = new List<DateTime>();

            string line = chatReader.ReadLine();
            while (line != null)
            {
                LogLine logLine = logReader.ReadChatLine(line);

                if (logLine.Success)
                {
                    if (chatState == 0)
                    {
                        if (logLine.Parameters[0].EndsWith("JJCraft系统记录竞技场开始,战斗记录已自动开启,加油!"))
                        {
                            combatTimePoints.Add(logLine.Time);
                            chatState = 1;
                        }
                    }
                    else
                    {
                        if (logLine.Parameters[0].EndsWith("JJCraft系统记录竞技场结束,战斗记录已自动停止."))
                        {
                            combatTimePoints.Add(logLine.Time);
                            chatState = 0;
                        }
                    }
                }

                line = chatReader.ReadLine();
                lineCount++;

                if (lineCount % 10 == 1)
                {
                    (sender as BackgroundWorker).ReportProgress((int)(chatReader.BaseStream.Position * 10 / chatReader.BaseStream.Length), result);
                }
            }
            chatReader.Close();

            if (combatTimePoints.Count >= 2)
            {
                Combat currentCombat = new Combat();

                int currentTimePoint = 0;
                DateTime combatBegin = combatTimePoints[currentTimePoint];
                DateTime combatEnd = combatTimePoints[currentTimePoint + 1];

                StreamReader reader = new StreamReader(Properties.Settings.Default.LastLogFile, Encoding.UTF8);

                line = reader.ReadLine();
                while (line != null)
                {
                    LogLine logLine = logReader.ReadLine(line);

                    if (logLine.Success)
                    {
                        if (logLine.Time >= combatBegin && logLine.Time < combatEnd)
                        {
                            currentCombat.ReadLog(logLine);
                        }
                        else if (logLine.Time >= combatEnd)
                        {
                            currentCombat.End();
                            if (currentCombat.IsWellFormed)
                            {
                                result.Combats.Add(currentCombat);
                            }

                            currentCombat = new Combat();

                            currentTimePoint += 2;
                            if (currentTimePoint + 1 < combatTimePoints.Count)
                            {
                                combatBegin = combatTimePoints[currentTimePoint];
                                combatEnd = combatTimePoints[currentTimePoint + 1];
                            }
                            else
                            {
                                break;
                            }
                        }
                    }

                    line = reader.ReadLine();

                    lineCount++;
                    if (lineCount % 100 == 1)
                    {
                        (sender as BackgroundWorker).ReportProgress((int)(10 + reader.BaseStream.Position * 90 / reader.BaseStream.Length), result);
                    }
                }
                reader.Close();

                currentCombat.End();
                if (currentCombat.IsWellFormed)
                {
                    result.Combats.Add(currentCombat);
                }
            }

            e.Result = result;
        }

        private void buttonClear_Click(object sender, RoutedEventArgs e)
        {
            buttonClear.Visibility = Visibility.Collapsed;
            groupResults.Visibility = Visibility.Collapsed;
            listResults.Items.Clear();
        }

        private void buttonReport_Click(object sender, RoutedEventArgs e)
        {
            if (listResults.SelectedItems.Count == 0)
            {
                MessageBox.Show("请选择需要生成报告的战役.", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
                return;
            }

            buttonReport.IsEnabled = false;

            char[] invalidChars = System.IO.Path.GetInvalidFileNameChars();

            foreach (object result in listResults.SelectedItems)
            {
                Combat combat = (result as StackPanel).Tag as Combat;

                string[] friends = new string[combat.Friends.Count];
                string[] enemies = new string[combat.Enemies.Count];

                for(int i=0;i<friends.Length;++i)
                {
                    friends[i] = ClassManager.Singleton.GetClassShortName(combat.Friends[i].Class);
                }

                for(int i=0;i<enemies.Length;++i)
                {
                    enemies[i] = ClassManager.Singleton.GetClassShortName(combat.Enemies[i].Class);
                }

                friends = friends.OrderBy(item => item).ToArray();
                enemies = enemies.OrderBy(item => item).ToArray();

                string report = combat.GenerateReport();

                string resultStr = string.Empty;
                switch (combat.Result)
                {
                    case CombatResult.Win:
                        resultStr = "胜";
                        break;
                    case CombatResult.Lose:
                        resultStr = "败";
                        break;
                    case CombatResult.DrawGame:
                        resultStr = "平";
                        break;
                }

                string reportFileName = String.Format("JJCraft {0} {1} {2}VS{3}.htm", combat.StartTime.ToString("yyyy.MM.dd HH.mm.ss", CultureInfo.InvariantCulture), resultStr, String.Join("", friends), String.Join("", enemies));
                StringBuilder reportFileNameBuilder = new StringBuilder();
                for (int i = 0; i < reportFileName.Length; ++i)
                {
                    if (!invalidChars.Contains(reportFileName[i]))
                    {
                        reportFileNameBuilder.Append(reportFileName[i]);
                    }
                }

                reportFileName = reportFileNameBuilder.ToString();

                string reportFileFullName = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, reportFileName);

                File.WriteAllText(reportFileFullName, report, Encoding.UTF8);

                System.Diagnostics.Process.Start(reportFileFullName);
            }

            buttonReport.IsEnabled = true;
        }
    }
}
